
#pragma once

#include <tbb/parallel_reduce.h>
#include <tbb/blocked_range.h>
#include <tbb/tick_count.h>
#include "Common.h"

using namespace ttg::math;
using namespace tbb;

class tbbCountingKernel
{
	private:
		PrimeFinderPool *pool;
		ttg::math::uint64 res;
	public:
		//Main constructor.
		inline tbbCountingKernel(PrimeFinderPool *pool)
		{
			this->pool = pool;
			res = 0;
		}
		//Constructor for TBB.
		inline tbbCountingKernel(tbbCountingKernel &kernel, split)
		{
			this->pool = kernel.pool;
			res = kernel.res;
		}
		//Returns accumulated result.
		inline ttg::math::uint64 getResult()
		{ return res; }
		//Counts prime numbers.
		inline void operator() (const tbb::blocked_range<uint64> &range)
		{ res += pool->findPrimes(range.begin(), range.end()); }
		//Joints result of the different kernels.
		inline void join(tbbCountingKernel &kernel)
		{ res += kernel.res; }
};

std::pair<uint64, double> tbbPrimes(uint64 n)
{
	//Creating auxiliary objects.
	PrimeFinderPool pool;
	tbbCountingKernel kernel(&pool);
	//Counting.
	tick_count t_start = tick_count::now();
	parallel_reduce(blocked_range<uint64>(0, n + 1), kernel, auto_partitioner());
	tick_count t_end = tick_count::now();
	//Returning result and elapsed time.
	return std::make_pair(kernel.getResult(), (t_end - t_start).seconds());
}